package com.rhf.core.db.factories;

import java.lang.reflect.Field;

import com.rhf.core.commons.logging.AppLog;
import com.rhf.core.commons.logging.AppLogManager;
import com.rhf.core.commons.properties.PropertiesManager;

/**
 * @author fabiensaulnier
 */
class BaseFactory {

	/**
	 * Identifiant de l'objet a instancier
	 */
	private String instance;

	/**
	 * Logger
	 */
	AppLog appLog = null;

	/**
	 * Nom par défaut de la base de données
	 */
	public final static String DATA_BASE_NAME = "postgresql";

	/**
	 * @param instance
	 */
	private BaseFactory(String instance) {

		// Logger
		this.appLog = AppLogManager.getDaoLogger();

		// Initisalisation de l'instance
		this.instance = instance;

		this.appLog.debug("Recuperation d'une instance de [" + instance + "]");

	}

	/**
	 * Controle si l'identifiant de l'instance est enregistré
	 * 
	 * @return Vrai si l'identifiant de l'instance est enregistré sinon faux
	 */
	private boolean checkInstance() {

		boolean isInstance = false;
		try {
			// Récupération le nom du package courant
			String packageName = this.getClass().getPackage().getName();

			// Récupération le nom de la casse
			String className = packageName.concat(".RegistryInstance");

			// Récupération le nom de la Classe java de className
			Class<?> classDecorator = Class.forName(className);

			// Récupération les champs déclarés
			Field fields[] = classDecorator.getDeclaredFields();
			if (fields != null) {
				boolean nextStep = true;
				int i = 0;
				while (i < fields.length && nextStep) {
					Field field = fields[i];
					String fieldName = field.getName();
					String fieldValue = field.get(fieldName).toString();
					if (fieldValue == null) {
						fieldValue = "";
					}
					if (field != null && fieldValue.equals(this.instance)) {
						nextStep = false;
						isInstance = true;
					}
					i++;
				}
			}

		} catch (Exception e) {
			this.appLog.error("Erreur lors du controle de l'instance" + e);
			isInstance = false;
		}

		if (isInstance) {
			this.appLog.debug("L'instance [" + this.instance + "] est enregistre : OK ");
		} else {
			this.appLog.debug("L'instance [" + this.instance + "] n'est pas enregistre : KO ");
		}
		return isInstance;
	}

	/**
	 * Retourne un objet identifié par instance
	 * 
	 * @return un objet identifié par instance
	 */
	protected Object getInstance() {

		try {
			// Récupére le nom du package courant
			String packageName = this.getClass().getPackage().getName();

			// Récupération du nom de la base de données
			String databaseName = PropertiesManager.getProperties().getString("RHF_BASE_DE_DONNES", DATA_BASE_NAME);

			// Récupération du package des implémentations
			String packageImplemenationName = packageName.replaceAll("factories$", "implementations." + databaseName + ".");

			// Récupération du nom de la classe de l'implétmentation
			String className = packageImplemenationName.concat(this.instance + "Imp");

			this.appLog.debug("Classe a charger " + className);

			// Récupération de la classe java
			return Class.forName(className).newInstance();

		} catch (Exception e) {
			this.appLog.error("Impossible de recuperer une instance de l'objet ", e);
		}
		return null;
	}

	/**
	 * Retourne une instance de instance
	 * 
	 * @param instanceName
	 * @return
	 */
	protected static Object getInstance(String instanceName) {

		// Récupération de l'objet factorie
		BaseFactory baseFactory = new BaseFactory(instanceName);

		// Contréle de l'existence de l'instance
		if (baseFactory.checkInstance()) {

			// Object instancié
			return baseFactory.getInstance();
		}

		return null;
	}
}
